Skip to main content

Working with Connections in ApertureDB

Connections are a way to represent relationships between objects in ApertureDB like works_at, contains, etc

# Connector class offers a way to connect to an instance of ApertureDB
from aperturedb import Connector

db = Connector.Connector("aperturedb.local", user="admin", password="admin")

# Simple query to see how the database is doing
# https://docs.aperturedata.io/query_language/Reference/db_commands/GetStatus
query = [{
"GetStatus": {
}
}]

# Execute the query to get back a JSON response for GetStatus
response, blobs = db.query(query)

db.print_last_response()
[
{
"GetStatus": {
"info": "OK",
"status": 0,
"system": "ApertureDB",
"version": "0.15.11"
}
}
]

One way to introduce new connections in the database is through our query language

For bulk additions, we recommend using the Python SDK loaders

We of course need a couple of objects to exist in order to connect them

More details about connection commands here and about the parameter "connect" here

query = [{
"AddEntity": {
"_ref": 1, # We can assign a numerical representation (handle) to the result of this query and refer to it elsewhere in this transaction
"class": "Food",
"properties": {
"name": "Focaccia",
"type": "bread",
"fresh": True
},
"if_not_found": {
"name": ["==", "Focaccia"]
}
}}, {
"AddImage": {
"_ref": 2, # Give another (unique within this query) handle to this command
"properties": {
"name": "Focaccia",
"my_id": "focaccia_brittany1",
"location": "Brittany",
"place": "restaurant"
},
"if_not_found": {
"my_id": ["==", "focaccia_brittany1"]
}
}}, {
"AddConnection": { # Now connect the results of the previous two commands using their handles, also see connect:{} parameter
"class": "self_image", # Connections themselves can have classes
"src": 1, # reference to 'Focaccia' entity added above
"dst": 2, # reference to 'Focaccia' image added above
"properties": { # Connections can also have their own set of key,value properties
"best_image": True
}
}
}]

# Read the image data as a binary blob
fd = open("input/images/focaccia_brittany.jpg", 'rb')
image_arr = [ fd.read() ]
fd.close()

response, blobs = db.query(query, image_arr)

db.print_last_response()
[
{
"AddEntity": {
"status": 0
}
},
{
"AddImage": {
"status": 0
}
},
{
"AddConnection": {
"status": 0
}
}
]

Verify this connection was added to the database and read all its properties

query = [{
"FindConnection": {
"with_class": "self_image", # Every connection belongs to a class, in this case self_image
"results": {
"all_properties": True
}
}
}]

response, blobs = db.query(query)

db.print_last_response()
[
{
"FindConnection": {
"connections": [
{
"_uniqueid": "13.0.47894344407481",
"best_image": true
}
],
"returned": 1,
"status": 0
}
}
]

Use the connection to traverse and find neighbors

Queries can use the is_connected_to parameter to traverse connections in the ApertureDB graph.

from aperturedb import NotebookHelpers as nh   # Our helper package for image displays and other utilities

query = [{
"FindEntity": {
"_ref": 1,
"with_class": "Food",
"constraints": {
"name": ["==", "Focaccia"]
},
"results": {
"list": ["name", "type"] # Retrieve only the properties 'name' and 'type'.
}
}}, {
"FindImage": {
"is_connected_to": { # Look for images that have connections to the entity found above.
"ref": 1,
"connection_class": "self_image", # Only consider connections of the 'self-image' class
"constraints": {
"best_image": ["==", True] # Only consider connections with the property 'best_image' equal to 'True'
}
},
"operations": [{ # Original image is large. We just need a thumbnail here
"type": "resize",
"height": 300,
"width": 300
} ],
"results": {
"list": ["name", "my_id"]
}
}
}]

response, blobs = db.query(query)

db.print_last_response()
nh.display(blobs)
[
{
"FindEntity": {
"entities": [
{
"name": "Focaccia",
"type": "bread"
}
],
"returned": 1,
"status": 0
}
},
{
"FindImage": {
"blobs_start": 0,
"entities": [
{
"_blob_index": 0,
"my_id": "focaccia_brittany1",
"name": "Focaccia"
}
],
"returned": 1,
"status": 0
}
}
]

png

Use UpdateConnection if any of the attributes need a new value or your application now needs a new attribute in existing entities

query = [{
"UpdateConnection": {
"with_class": "self_image", # Find any connections of class 'self_image' ...
"constraints": {
"best_image": ["==", True] # With the property 'best_image' equal to 'True' ...
},
"properties": {
"best_image": False, # And update them by setting 'best_image' to 'False'.
},
}
}]

response, blobs = db.query(query)

db.print_last_response()
[
{
"UpdateConnection": {
"count": 1,
"status": 0
}
}
]
# Check that the connection was modified
query = [{
"FindEntity": {
"_ref": 1,
"with_class": "Food",
"constraints": {
"name": ["==", "Focaccia"]
},
"results": {
"list": ["name", "type"]
}
}}, {
"FindImage": {
"is_connected_to": {
"ref": 1,
"connection_class": "self_image",
"constraints": {
"best_image": ["==", True] # Look for a connection with the old 'best_image' value.
}
},
"operations": [{
"type": "resize",
"height": 300,
"width": 300
} ],
"results": {
"list": ["name", "my_id"]
}
}
}]

response, blobs = db.query(query)

# We expect that this search shouldn't find anything.
db.print_last_response()
nh.display(blobs)
[
{
"FindEntity": {
"entities": [
{
"name": "Focaccia",
"type": "bread"
}
],
"returned": 1,
"status": 0
}
},
{
"FindImage": {
"returned": 0,
"status": 0
}
}
]

We can now delete the connection

query = [{
"DeleteConnection": {
"with_class": "self_image" # delete all connections with class 'self_image'
}
}
]

response, blobs = db.query(query)

db.print_last_response()
[
{
"DeleteConnection": {
"count": 1,
"status": 0
}
}
]

We can verify that the connection is no longer in the database with another FindConnection

query = [{
"FindConnection": {
"with_class": "self_image", # Look for the connections that we deleted
"results": {
"all_properties": True
}
}
}]

response, blobs = db.query(query)

# We expect 0 results
db.print_last_response()
[
{
"FindConnection": {
"returned": 0,
"status": 0
}
}
]